package com.boot.mgt.service.impl

import com.boot.config.datasource.OracleDb
import com.boot.core.result.ResultEnum
import com.boot.core.result.ResultTo
import com.boot.core.util.ManagerKit
import com.boot.mgt.dao.oracle.OracleTAcdFileMapper
import com.boot.mgt.model.vo.Accident
import com.boot.mgt.model.vo.Death
import com.boot.mgt.model.vo.Injured
import com.boot.mgt.model.vo.StatisticsResultVo
import com.boot.mgt.service.StatisticsService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.text.SimpleDateFormat
import java.util.*
import com.boot.config.ParamConfig
import com.googlecode.jsonrpc4j.spring.AutoJsonRpcServiceImpl


/**
 * @author kawins
 * createTime 2018-12-09 17:19
 */
@AutoJsonRpcServiceImpl
@Service
class StatisticsServiceImpl : StatisticsService {

    @Autowired
    private lateinit var tAcdFileMapper: OracleTAcdFileMapper
    @Autowired
    private lateinit var paramConfig: ParamConfig

    @OracleDb
    override fun accident(start_time: Date, end_time: Date, deathStart: Int, deathEnd: Int): ResultTo {
        if (!ManagerKit.isCaptain()) {
            return ResultTo(ResultEnum.OPERATION_FAILED, "无权限")
        }

        val now = tAcdFileMapper.selectAccidentCount(FORMAT.format(start_time), FORMAT.format(addOneDay(end_time)),
                deathStart, deathEnd, ALL_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        val old = tAcdFileMapper.selectAccidentCount(FORMAT.format(addOneDay(lastYear(start_time))),
                FORMAT.format(lastYear(end_time)), deathStart, deathEnd, ALL_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        val accident = Accident()
        val death = Death()
        val injured = Injured()
        accident.accidentCount = now.accidentsCount ?: 0
        accident.accidentPercentage = (now.accidentsCount ?: 0) - (old.accidentsCount ?: 0)
        death.deathCount = now.deathCount ?: 0
        death.deathPercentage = (now.deathCount ?: 0) - (old.deathCount ?: 0)
        injured.injuredCount = now.injuredCount ?: 0
        injured.injuredPercentage = (now.injuredCount ?: 0) - (old.injuredCount ?: 0)

        val year5 = dateYear(5)
        val accidentYear = linkedMapOf<String, Int>()
        val deathYear = linkedMapOf<String, Int>()
        val injuredYear = linkedMapOf<String, Int>()
        val countYearList = tAcdFileMapper.selectAccidentCountGroup(deathStart, deathEnd, 5, YEAR_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        var flag: Boolean
        for (s in year5) {
            flag = false
            for (statisticsCountVo in countYearList) {
                if (s == statisticsCountVo.dateStr) {
                    flag = true
                    accidentYear[s] = statisticsCountVo.accidentsCount ?: 0
                    deathYear[s] = statisticsCountVo.deathCount ?: 0
                    injuredYear[s] = statisticsCountVo.injuredCount ?: 0
                }
            }
            if (!flag) {
                accidentYear[s] = 0
                deathYear[s] = 0
                injuredYear[s] = 0
            }
        }
        accident.year5 = accidentYear
        death.year5 = deathYear
        injured.year5 = injuredYear

        val month12 = dateMonth(12)
        val accidentMonth = linkedMapOf<String, Int>()
        val deathMonth = linkedMapOf<String, Int>()
        val injuredMonth = linkedMapOf<String, Int>()
        val countMonthList = tAcdFileMapper.selectAccidentCountGroup(deathStart, deathEnd, 12, MONTH_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        for (s in month12) {
            flag = false
            for (statisticsCountVo in countMonthList) {
                if (s == statisticsCountVo.dateStr) {
                    flag = true
                    accidentMonth[s] = statisticsCountVo.accidentsCount ?: 0
                    deathMonth[s] = statisticsCountVo.deathCount ?: 0
                    injuredMonth[s] = statisticsCountVo.injuredCount ?: 0
                    continue
                }
            }
            if (!flag) {
                accidentMonth[s] = 0
                deathMonth[s] = 0
                injuredMonth[s] = 0
            }
        }
        accident.month12 = accidentMonth
        death.month12 = deathMonth
        injured.month12 = injuredMonth

        val result = StatisticsResultVo().apply {
            this.accident = accident
            this.death = death
            this.injured = injured
        }
        return ResultTo()
                .setData("statistics", result)
    }

    @OracleDb
    override fun accidentRpc(start_time: Date, end_time: Date, deathStart: Int, deathEnd: Int, police_level: Int): ResultTo {
        if (police_level!=1) {
            return ResultTo(ResultEnum.OPERATION_FAILED, "无权限")
        }

        val now = tAcdFileMapper.selectAccidentCount(FORMAT.format(start_time), FORMAT.format(addOneDay(end_time)),
                deathStart, deathEnd, ALL_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        val old = tAcdFileMapper.selectAccidentCount(FORMAT.format(addOneDay(lastYear(start_time))),
                FORMAT.format(lastYear(end_time)), deathStart, deathEnd, ALL_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        val accident = Accident()
        val death = Death()
        val injured = Injured()
        accident.accidentCount = now.accidentsCount ?: 0
        accident.accidentPercentage = (now.accidentsCount ?: 0) - (old.accidentsCount ?: 0)
        death.deathCount = now.deathCount ?: 0
        death.deathPercentage = (now.deathCount ?: 0) - (old.deathCount ?: 0)
        injured.injuredCount = now.injuredCount ?: 0
        injured.injuredPercentage = (now.injuredCount ?: 0) - (old.injuredCount ?: 0)

        val year5 = dateYear(5)
        val accidentYear = linkedMapOf<String, Int>()
        val deathYear = linkedMapOf<String, Int>()
        val injuredYear = linkedMapOf<String, Int>()
        val countYearList = tAcdFileMapper.selectAccidentCountGroup(deathStart, deathEnd, 5, YEAR_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        var flag: Boolean
        for (s in year5) {
            flag = false
            for (statisticsCountVo in countYearList) {
                if (s == statisticsCountVo.dateStr) {
                    flag = true
                    accidentYear[s] = statisticsCountVo.accidentsCount ?: 0
                    deathYear[s] = statisticsCountVo.deathCount ?: 0
                    injuredYear[s] = statisticsCountVo.injuredCount ?: 0
                }
            }
            if (!flag) {
                accidentYear[s] = 0
                deathYear[s] = 0
                injuredYear[s] = 0
            }
        }
        accident.year5 = accidentYear
        death.year5 = deathYear
        injured.year5 = injuredYear

        val month12 = dateMonth(12)
        val accidentMonth = linkedMapOf<String, Int>()
        val deathMonth = linkedMapOf<String, Int>()
        val injuredMonth = linkedMapOf<String, Int>()
        val countMonthList = tAcdFileMapper.selectAccidentCountGroup(deathStart, deathEnd, 12, MONTH_DATE_FORMATTER, paramConfig.documents.acdFileTableName)
        for (s in month12) {
            flag = false
            for (statisticsCountVo in countMonthList) {
                if (s == statisticsCountVo.dateStr) {
                    flag = true
                    accidentMonth[s] = statisticsCountVo.accidentsCount ?: 0
                    deathMonth[s] = statisticsCountVo.deathCount ?: 0
                    injuredMonth[s] = statisticsCountVo.injuredCount ?: 0
                    continue
                }
            }
            if (!flag) {
                accidentMonth[s] = 0
                deathMonth[s] = 0
                injuredMonth[s] = 0
            }
        }
        accident.month12 = accidentMonth
        death.month12 = deathMonth
        injured.month12 = injuredMonth

        val result = StatisticsResultVo().apply {
            this.accident = accident
            this.death = death
            this.injured = injured
        }
        return ResultTo()
                .setData("statistics", result)
    }

    companion object {

        private val FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        const val ALL_DATE_FORMATTER: String = "yyyy-mm-dd hh24:mi:ss"
        const val MONTH_DATE_FORMATTER: String = "'yyyy-mm'"
        const val YEAR_DATE_FORMATTER: String = "'yyyy'"

        /**
         * count 步长
         */
        fun dateYear(count: Int): List<String> {
            val c = Calendar.getInstance()
            c.time = Date()
            val list = arrayListOf<String>()
            list.add(FORMAT.format(c.time).substring(0, 4))
            for (i in 1..(count - 1)) {
                c.add(Calendar.YEAR, -1)
                list.add(FORMAT.format(c.time).substring(0, 4))
            }
            list.reverse()
            return list
        }

        fun dateMonth(count: Int): List<String> {
            val c = Calendar.getInstance()
            c.time = Date()
            val list = arrayListOf<String>()
            list.add(FORMAT.format(c.time).substring(0, 7))
            for (i in 1..(count - 1)) {
                c.add(Calendar.MONTH, -1)
                list.add(FORMAT.format(c.time).substring(0, 7))
            }
            list.reverse()
            return list
        }

        fun lastYear(data: Date): Date {
            val c = Calendar.getInstance()
            c.time = data
            c.add(Calendar.YEAR, -1)
            return c.time
        }

        fun addOneDay(data: Date): Date {
            val c = Calendar.getInstance()
            c.time = data
            c.add(Calendar.DATE, +1)
            return c.time
        }
    }
}